﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Windows.Data;

namespace ICodeShare.UI.Utils.Helpers
{
    /// <summary>
    /// 提供用于限制TextBox输入字符的方法
    /// 同时可以设置当TextBox中的Text属性改变时立即更新绑定
    /// </summary>
    ///<example>
    /// 1.在Xaml中使用：
    ///   1)在xaml中添加引用 xmlns:textboxExt="clr-namespace:KB.DSN.ControlsAndStyles;assembly=KB.DSN.ControlsAndStyles"
    ///   2)在TextBox元素上设置属性 <TextBox textboxExt:TextBoxTextFilter.InvalidPattern="[^a-z0-9A-Z_]" />
    ///   3)如果需要在Text属性改变时立即更新绑定，设置<TextBox textboxExt:TextBoxTextFilter.InvalidPattern="[^a-z0-9A-Z_]"  textboxExt:TextBoxTextFilter.UpdateBindingWhenTextChanged="True" />
    /// 2.在C#中使用：
    ///   1)添加 using KB.DSN.ControlsAndStyles
    ///   2)代码 textBox.SetInvalidPattern("[^a-z0-9A-Z_]");
    /// 3.常用正则表达式：
    ///   1) [^\d\.]        ——只能输入数字和小数点
    ///   2) [^\d]          ——只能输入数字
    ///   3) [^a-z0-9A-Z_]  ——只能输入数字、字母和下划线
    /// </example>
    public static class TextBoxTextFilter
    {


        #region 扩展属性InvalidPattern

        public static string GetInvalidPattern(this TextBox textbox)
        {
            return (string)textbox.GetValue(InvalidPatternProperty);
        }

        public static void SetInvalidPattern(this TextBox textbox, string value)
        {
            textbox.SetValue(InvalidPatternProperty, value);
        }

        // Using a DependencyProperty as the backing store for InvalidPattern.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty InvalidPatternProperty =
            DependencyProperty.RegisterAttached("InvalidPattern", typeof(string), typeof(TextBoxTextFilter), new PropertyMetadata(string.Empty, OnInvalidPatternPropertyChanged));


        private static void OnInvalidPatternPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TextBox textBox = d as TextBox;
            string pattern = e.NewValue as string;

            if ((bool)textBox.GetValue(UpdateBindingWhenTextChangedProperty) == false)
            {
                if (string.IsNullOrEmpty(pattern))
                {
                    textBox.KeyUp -= new KeyEventHandler(textBox_KeyUp);
                    textBox.KeyDown -= new KeyEventHandler(textBox_KeyDown);
                }
                else
                {
                    textBox.KeyUp += new KeyEventHandler(textBox_KeyUp);
                    textBox.KeyDown += new KeyEventHandler(textBox_KeyDown);
                }
            }

        }

        #endregion

        #region 扩展属性UpdateBindingWhenTextChanged



        public static bool GetUpdateBindingWhenTextChanged(this TextBox textbox)
        {
            return (bool)textbox.GetValue(UpdateBindingWhenTextChangedProperty);
        }

        public static void SetUpdateBindingWhenTextChanged(this TextBox textbox, bool value)
        {
            textbox.SetValue(UpdateBindingWhenTextChangedProperty, value);
        }

        // Using a DependencyProperty as the backing store for UpdateBindingWhenTextChanged.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty UpdateBindingWhenTextChangedProperty =
            DependencyProperty.RegisterAttached("UpdateBindingWhenTextChanged", typeof(bool), typeof(TextBoxTextFilter), new PropertyMetadata(false, OnUpdateBindingWhenTextChangedPropertyChanged));


        private static void OnUpdateBindingWhenTextChangedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TextBox textBox = d as TextBox;
            bool value = (bool)e.NewValue;
            if (string.IsNullOrEmpty(textBox.GetValue(InvalidPatternProperty) as string))
            {
                if (value)
                {
                    textBox.KeyUp += new KeyEventHandler(textBox_KeyUp);
                    textBox.KeyDown += new KeyEventHandler(textBox_KeyDown);
                }
                else
                {
                    textBox.KeyUp -= new KeyEventHandler(textBox_KeyUp);
                    textBox.KeyDown -= new KeyEventHandler(textBox_KeyDown);

                }
            }
        }


        #endregion

        #region 扩展属性FilterParameters
        private static int GetOriCursorPosition(this TextBox textbox)
        {
            return (int)textbox.GetValue(OriCursorPositionProperty);
        }

        private static void SetOriCursorPosition(this TextBox textbox, int value)
        {
            textbox.SetValue(OriCursorPositionProperty, value);
        }

        // Using a DependencyProperty as the backing store for FilterParameters.  This enables animation, styling, binding, etc...
        private static readonly DependencyProperty OriCursorPositionProperty =
            DependencyProperty.RegisterAttached("OriCursorPosition", typeof(int), typeof(TextBoxTextFilter), new PropertyMetadata(0, OnOriCursorPositionPropertyChanged));



        private static void OnOriCursorPositionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

        }

        #endregion


        /// <summary>
        /// KeyUp时，将非法字符删掉，并将TextBox的SelectionStart值还原为KeyDown时的值
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        static void textBox_KeyUp(object sender, KeyEventArgs e)
        {


            TextBox textBox = sender as TextBox;

            Debug.Assert(textBox != null, "sender should be a non-null TextBox!");
            Debug.Assert(e != null, "e should not be null!");


            int position = (int)textBox.GetValue(OriCursorPositionProperty);
            string pattern = textBox.GetValue(InvalidPatternProperty) as string;
            if (!string.IsNullOrEmpty(pattern))
            {
                if (Regex.IsMatch(textBox.Text, pattern))
                {
                    textBox.Text = Regex.Replace(textBox.Text, pattern, "");
                    if (position > textBox.Text.Length)
                        textBox.SelectionStart = textBox.Text.Length;
                    else
                        textBox.SelectionStart = position;
                }
                else
                {
                    if ((bool)textBox.GetValue(UpdateBindingWhenTextChangedProperty))
                    {
                        BindingExpression be = textBox.GetBindingExpression(TextBox.TextProperty);
                        if (be != null)
                            be.UpdateSource();
                    }
                }
            }
            else
            {
                if ((bool)textBox.GetValue(UpdateBindingWhenTextChangedProperty))
                {
                    BindingExpression be = textBox.GetBindingExpression(TextBox.TextProperty);
                    if (be != null)
                        be.UpdateSource();
                }
            }
        }


        /// <summary>
        /// KeyDown时，记录TextBox的SelectionStart
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        static void textBox_KeyDown(object sender, KeyEventArgs e)
        {
            TextBox textBox = sender as TextBox;

            Debug.Assert(textBox != null, "sender should be a non-null TextBox!");
            Debug.Assert(e != null, "e should not be null!");

            textBox.SetValue(OriCursorPositionProperty, textBox.SelectionStart);
        }

    }
}
